package com.guguskins.back.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guguskins.back.common.constant.InventoryConstant;
import com.guguskins.back.common.constant.RedisConstant;
import com.guguskins.back.common.exception.GlobalMsgException;
import com.guguskins.back.entity.*;
import com.guguskins.back.entity.bo.*;
import com.guguskins.back.entity.vo.*;
import com.guguskins.back.mapper.GuUserMapper;
import com.guguskins.back.service.*;
import com.guguskins.back.utils.*;
import com.guguskins.back.utils.steam.SteamLoginUtil;
import com.guguskins.back.utils.steam.SteamUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author mybatis-plus
 * @since 2021-05-08
 */
@Service
@Slf4j
public class GuUserServiceImpl extends ServiceImpl<GuUserMapper, GuUser> implements GuUserService {

    @Autowired
    private GuUserMapper userMapper;

    @Autowired
    private GuUserLevelService userLevelService;

    @Autowired
    private GuInventoryService inventoryService;

    @Autowired
    private GuBoxService boxService;

    @Autowired
    private GuGoodsService goodsService;

    @Autowired
    private GuPropService propService;

    @Autowired
    private GuPropNumService propNumService;

    @Autowired
    private GuHenHouseTaskService henHouseTaskService;

    @Autowired
    private GuSystemConfigService systemConfigService;

    @Autowired
    private GuCurrencyRecordService currencyRecordService;

    @Autowired
    private GuInviteNumService inviteNumService;

    @Override
    public PageVo<GuUser> backPage(int p, int size, String searchKey) {
        IPage<GuUser> iPage = new Page<>(p, size);
        iPage = this.page(iPage, new LambdaQueryWrapper<GuUser>() {
            {
                like(!ObjectUtils.isEmpty(searchKey), GuUser::getUserNickname, searchKey);
            }
        });
        return new PageVo<>(iPage.getRecords(), iPage.getTotal());
    }

    @Override
    @Async
    public void sendCode(SendCodeBo sendCodeBo) {
        //判断邮箱是否被占用
        String account = sendCodeBo.getAccount();
        int count = this.count(new LambdaQueryWrapper<GuUser>() {
            {
                eq(GuUser::getUserAccount, account);
            }
        });
        if (count > 0) {
            throw new GlobalMsgException("手机号或邮箱已被占用");
        }
        String code = CommonUtil.generateNumberCode();
        //判断是邮箱还是手机号
        if (PhoneFormatCheckUtils.isPhoneLegal(account)) {
            //发送短信验证码
            String message = QixintongUtil.sendMobileMessageByURL(account, "您的验证码为：" + code + "【惠多多】", 0);
            RedisUtil.setKey(RedisConstant.CODE_PREFIX + account, code, 10, TimeUnit.MINUTES);
        } else if (SendMailUtil.checkEmail(account)) {
            //验证邮箱有效性
            SendMailUtil.sendSimpleMail(account, "GUGUSKINS验证码", "您的邮箱验证码为：" + code);
            RedisUtil.setKey(RedisConstant.CODE_PREFIX + account, code, 10, TimeUnit.MINUTES);
        }
    }

    @Override
    public void sendCodeAuthentication(Long userId) {
        GuUser user = this.getById(userId);
        String userAccount = user.getUserAccount();
        if (ObjectUtils.isEmpty(userAccount)) {
            throw new GlobalMsgException("系统异常，请联系客服");
        }
        String code = CommonUtil.generateNumberCode();
        //判断是邮箱还是手机号
        if (PhoneFormatCheckUtils.isPhoneLegal(userAccount)) {
            //发送短信验证码
            String message = QixintongUtil.sendMobileMessageByURL(userAccount, "您的验证码为：" + code + "【惠多多】", 0);
            RedisUtil.setKey(RedisConstant.CHANGE_CODE_PREFIX + userAccount, code, 10, TimeUnit.MINUTES);
        } else if (SendMailUtil.checkEmail(userAccount)) {
            //验证邮箱有效性

            SendMailUtil.sendSimpleMail(userAccount, "GUGUSKINS验证码", "您的邮箱验证码为：" + code);
            RedisUtil.setKey(RedisConstant.CHANGE_CODE_PREFIX + userAccount, code, 10, TimeUnit.MINUTES);
        }
    }

    @Override
    @Async
    public void sendCodeAccount(SendCodeBo sendCodeBo) {
        CommonUtil.checkParams(sendCodeBo.getAccount());
        String code = CommonUtil.generateNumberCode();
        String account = sendCodeBo.getAccount();
        //判断是邮箱还是手机号
        if (PhoneFormatCheckUtils.isPhoneLegal(account)) {
            //发送短信验证码
            String message = QixintongUtil.sendMobileMessageByURL(account, "您的验证码为：" + code + "【惠多多】", 0);
            RedisUtil.setKey(RedisConstant.CHANGE_CODE_PREFIX + account, code, 10, TimeUnit.MINUTES);
        } else if (SendMailUtil.checkEmail(account)) {
            //验证邮箱有效性
            SendMailUtil.sendSimpleMail(account, "GUGUSKINS验证码", "您的邮箱验证码为：" + code);
            RedisUtil.setKey(RedisConstant.CHANGE_CODE_PREFIX + account, code, 10, TimeUnit.MINUTES);
        }
    }


    @Override
    public String login(UserBo userBo) {
        GuUser user = this.getOne(new LambdaQueryWrapper<GuUser>() {
            {
                eq(GuUser::getUserAccount, userBo.getUserAccount());
            }
        });
        if (ObjectUtils.isEmpty(user)) {
            throw new GlobalMsgException("用户未注册");
        }
        if (!MessageMD5.checkPassword(userBo.getUserPassword(), user.getUserPassword())) {
            throw new GlobalMsgException("密码错误");
        }
        //生成token
        return JwtUtil.generateToken(user.getUserId());
    }

    @Override
    public boolean register(RegisterUserBo registerUserBo) {

        String redisCode = RedisUtil.getValue(RedisConstant.CODE_PREFIX + registerUserBo.getUserAccount());
        if (!registerUserBo.getCode().equals(redisCode)) {
            throw new GlobalMsgException("验证码错误");
        }
        if (!registerUserBo.getUserPassword().equals(registerUserBo.getConfirmPassword())) {
            throw new GlobalMsgException("两次密码不一致");
        }
        //校验用户名是否存在
        int count = this.count(new LambdaQueryWrapper<GuUser>() {
            {
                eq(GuUser::getUserNickname, registerUserBo.getUserNickname());
            }
        });
        if (count > 0) {
            throw new GlobalMsgException("用户名已被占用");
        }
        GuUser user = new GuUser();
        user.setUserNickname(registerUserBo.getUserNickname());
        user.setUserAccount(registerUserBo.getUserAccount());
        user.setUserPassword(registerUserBo.getUserPassword());
        //生成验证码
        user.setUserInviteCode(Objects.requireNonNull(MessageMD5.encrypt(System.currentTimeMillis() + user.getUserNickname())).substring(0, 8));
        user.setUserInviteExp(DateUtil.getTime(systemConfigService.getSystemConfig().getConfigInviteCodeExp()));

        if (user.insert()) {
            //初始化各道具库存
            return propNumService.init(user);
        }
        return false;
    }

    @Override
    public GuUser userInfoBySteamId(String steamId) {
        CommonUtil.checkParams(steamId);

        GuUser user = this.getOneBySteamId(steamId);
        if (ObjectUtils.isEmpty(user)) {
            JSONArray playerSummaries = SteamUtil.getPlayerSummaries(steamId, systemConfigService.getSystemConfig().getConfigSteamKey());
            if (CollectionUtils.isEmpty(playerSummaries)) {
                log.error("steam账号未查询到：{}", steamId);
                throw new GlobalMsgException("未知steamId");
            } else {
                PlayerSummary playerSummary = playerSummaries.getJSONObject(0).toJavaObject(PlayerSummary.class);
                user = this.playerSummary2GuUser(null, playerSummary);
                user.setUserInviteCode(Objects.requireNonNull(MessageMD5.encrypt(System.currentTimeMillis() + user.getUserNickname())).substring(0, 8));
                user.setUserInviteExp(DateUtil.getTime(systemConfigService.getSystemConfig().getConfigInviteCodeExp()));
                user.insert();
                //插入道具
                propNumService.init(user);
            }
        }
        return user;
    }

    @Override
    public GuUser getOneBySteamId(String steamId) {
        GuUser user = this.getOne(new LambdaQueryWrapper<GuUser>() {
            {
                eq(GuUser::getUserSteamId, steamId);
            }
        });
        if (!ObjectUtils.isEmpty(user) && !ObjectUtils.isEmpty(user.getUserAccount())) {
            if (SendMailUtil.checkEmail(user.getUserAccount())) {
                user.setUserAccountShow(user.getUserAccount().replaceAll("(.{2}).+(.{2}@.+)", "$1***$2"));
            } else if (PhoneFormatCheckUtils.isPhoneLegal(user.getUserAccount())) {
                user.setUserAccountShow(PhoneFormatCheckUtils.replace(user.getUserAccount()));
            }
        }
        return user;
    }

    @Override
    public PageVo<GuUser> getPageByRollId(int p, int size, long rollId) {
        PageVo<GuUser> pageVo = new PageVo<>();
        int index = (p - 1) * size;
        List<GuUser> pageData = userMapper.getPageDataByRollId(index, size, rollId);
        pageVo.setData(pageData);
        Long count = userMapper.getCountByRollId(rollId);
        pageVo.setTotal(count);
        return pageVo;
    }

    @Override
    public UserInfoVo getUserInfo(Long userId) {
        UserInfoVo userInfoVo = new UserInfoVo();
        //查询基本信息
        GuUser user = this.getById(userId);
        userInfoVo.setUser(user);
        List<GuUserLevel> userLevelList = userLevelService.list(new LambdaQueryWrapper<GuUserLevel>() {
            {
                orderByDesc(GuUserLevel::getUlValue);
            }
        });
        //设置等级
        UserLevelVo userLevelVo = new UserLevelVo();
//        userLevelVo.setLevelExperience(user.getUserLevelExperience());
        GuUserLevel userNowLevel = userLevelList.stream().filter(userLevel -> user.getUserLevelExperience().compareTo(userLevel.getUlExperience()) >= 0).max(Comparator.comparing(GuUserLevel::getUlExperience)).orElse(new GuUserLevel());
        GuUserLevel userNextLevel = userLevelList.stream().filter(userLevel -> user.getUserLevelExperience().compareTo(userLevel.getUlExperience()) < 0).min(Comparator.comparing(GuUserLevel::getUlExperience)).orElse(null);
        userLevelVo.setUserLevel(userNowLevel.getUlValue());
        userLevelVo.setUserLevelName(userNowLevel.getUlName());
        userLevelVo.setLevelImage(userNowLevel.getUlImage());
//        userLevelVo.setMinLevelExperience(userNowLevel.getUlExperience());
//        userLevelVo.setMaxLevelExperience(userNextLevel.getUlExperience());
        //计算当前级别经验值
        if (ObjectUtils.isEmpty(userNextLevel)) {
            GuUserLevel level = userLevelList.stream().filter(userLevel -> userNowLevel.getUlExperience().compareTo(userLevel.getUlExperience()) > 0).max(Comparator.comparing(GuUserLevel::getUlExperience)).orElse(new GuUserLevel());
            userLevelVo.setUserLevelExperience(userNowLevel.getUlExperience().subtract(level.getUlExperience()));
            //当前经验值
            userLevelVo.setUserExperience(userNowLevel.getUlExperience().subtract(level.getUlExperience()));
        } else {
            userLevelVo.setUserLevelExperience(userNextLevel.getUlExperience().subtract(userNowLevel.getUlExperience()));
            //当前经验值
            userLevelVo.setUserExperience(user.getUserLevelExperience().subtract(userNowLevel.getUlExperience()));
        }
        userInfoVo.setUserLevelVo(userLevelVo);

        //设置最佳箱子
        GuInventory bestBoxInventory = inventoryService.bestInventory(userId, Arrays.asList(InventoryConstant.Source.BLIND_BOX, InventoryConstant.Source.PROP_STAND));
        if (!ObjectUtils.isEmpty(bestBoxInventory)) {
            GuBox box = boxService.getBox(bestBoxInventory.getInventorySourceId());
            box.setGoodsIconUrl(box.getGoodsList().stream().max(Comparator.comparing(GuGoods::getGoodsPrice)).orElse(new GuGoods()).getGoodsIconUrl());
            box.setGoodsList(null);
            userInfoVo.setBox(box);
        }

        //设置高价值奖品
        GuInventory bestGoodsInventory = inventoryService.bestInventory(userId, null);
        if (!ObjectUtils.isEmpty(bestGoodsInventory)) {
            GuGoods goods = goodsService.getOne(new LambdaQueryWrapper<GuGoods>() {
                {
                    select(GuGoods::getGoodsId, GuGoods::getGoodsName, GuGoods::getGoodsPrice, GuGoods::getGoodsIconUrl, GuGoods::getGoodsLevel);
                    eq(GuGoods::getGoodsId, bestGoodsInventory.getInventoryItemId());
                }
            });
            userInfoVo.setGoods(goods);
        }

        //获取鸡舍信息
        List<GuProp> henHouseList = propService.getHenHouseList(userId);
        List<LocalDateTime> localDateTimes = new ArrayList<>();
        henHouseList.forEach(henHouse -> {
            if (!ObjectUtils.isEmpty(henHouse.getPropState()) && !henHouse.getPropState().equals(0)) {
                HenHouseTaskVo detail = henHouseTaskService.getDetail(userId, henHouse.getPnId());
                if (!ObjectUtils.isEmpty(detail) && detail.getState() != 0) {
                    localDateTimes.add(detail.getHenHouseTask().getTaskExpirationTime());
                }
            }
        });

        userInfoVo.setHenHouseTaskTime(localDateTimes.stream().min(LocalDateTime::compareTo).orElse(null));
        return userInfoVo;
    }

    @Override
    public GuUser getUserInfoSimple(Long userId) {
        return this.getById(userId);
    }

    @Override
    public GuUser uploadUserInfo(GuUser user) {
//        CommonUtil.checkParams(user.getUserSteamId(), user.getUserNickname(), user.getUserImage(), user.getUserTradingUrl());
        GuUser guUser = this.getById(user.getUserId());
        if (!ObjectUtils.isEmpty(user.getUserNickname())) {
            int count = this.count(new LambdaQueryWrapper<GuUser>() {
                {
                    ne(GuUser::getUserId, user.getUserId());
                    eq(GuUser::getUserNickname, user.getUserNickname());
                }
            });
            if (count > 0) {
                throw new GlobalMsgException("昵称已存在");
            }
            guUser.setUserNickname(user.getUserNickname());
        }
        guUser.setUserImage(user.getUserImage());
        guUser.setUserTradingUrl(user.getUserTradingUrl());
        guUser.updateById();
        return guUser;
    }

    @Override
    public boolean changePassword(Long userId, ChangePasswordBo changePasswordBo) {
        if (!changePasswordBo.getPassword().equals(changePasswordBo.getConfirmPassword())) {
            throw new GlobalMsgException("两次密码不一致");
        }
        GuUser user = this.getById(userId);
        String userAccount = user.getUserAccount();
        if (ObjectUtils.isEmpty(userAccount)) {
            throw new GlobalMsgException("系统异常，请联系客服");
        }

        //判断是邮箱还是手机号
        if (PhoneFormatCheckUtils.isPhoneLegal(userAccount)) {
            //发送短信验证码

        } else if (SendMailUtil.checkEmail(userAccount)) {
            String redisCode = RedisUtil.getValue(RedisConstant.CHANGE_CODE_PREFIX + userAccount);
            if (!changePasswordBo.getCode().equals(redisCode)) {
                throw new GlobalMsgException("验证码错误");
            }
        }
        // 加密密码
        user.setUserPassword(MessageMD5.encrypt(changePasswordBo.getPassword()));
        //
        return user.updateById();
    }

    @Override
    public boolean changePasswordByAccount(ChangePasswordBo changePasswordBo) {
        if (ObjectUtils.isEmpty(changePasswordBo.getAccount())) {
            throw new GlobalMsgException("用户手机号不能为空");
        }
        if (!changePasswordBo.getPassword().equals(changePasswordBo.getConfirmPassword())) {
            throw new GlobalMsgException("两次密码不一致");
        }
        GuUser user = this.getOne(new LambdaQueryWrapper<GuUser>() {
            {
                eq(GuUser::getUserAccount, changePasswordBo.getAccount());
            }
        });
        if (ObjectUtils.isEmpty(user)) {
            throw new GlobalMsgException("手机号未注册");
        }
        String redisCode = RedisUtil.getValue(RedisConstant.CHANGE_CODE_PREFIX + changePasswordBo.getAccount());
        if (!changePasswordBo.getCode().equals(redisCode)) {
            throw new GlobalMsgException("验证码错误");
        }
        // 加密密码
        user.setUserPassword(MessageMD5.encrypt(changePasswordBo.getPassword()));
        //
        return user.updateById();
    }

    @Override
    public boolean addGuCurrency(Long userId, BigDecimal amount, BigDecimal originalAmount, Integer sourceType, Long sourceId, String sourceImage, String sourceName, String desc, String remark) {
        GuUser user = this.getById(userId);
        user.setUserGuCurrency(user.getUserGuCurrency().add(amount));
        if (user.updateById()) {
            GuCurrencyRecord currencyRecord = new GuCurrencyRecord();
            currencyRecord.setCrUserId(userId);
            currencyRecord.setCrSteamId(user.getUserSteamId());
            currencyRecord.setCrUserNickname(user.getUserNickname());
            currencyRecord.setCrAmount(amount);
            currencyRecord.setCrOriginalAmount(originalAmount);
            currencyRecord.setCrType(0);
            currencyRecord.setCrSourceType(sourceType);
            currencyRecord.setCrSourceId(sourceId);
            currencyRecord.setCrSourceImage(sourceImage);
            currencyRecord.setCrSourceName(sourceName);
            currencyRecord.setCrDesc(desc);
            currencyRecord.setCrRemark(remark);
            if (currencyRecord.insert()) {
                if (sourceType.equals(2)) {
                    //添加邀请记录
                    GuUserInvite userInvite = new GuUserInvite();
                    userInvite.setUserId(userId);
                    userInvite.setUserSteamId(user.getUserSteamId());
                    userInvite.setInviteUserId(sourceId);
                    userInvite.setType(2);
                    userInvite.setAmount(originalAmount);
                    userInvite.setPrizeAmount(amount);
                    userInvite.insert();

                    //添加经验
                    user.setUserInviteIncome(user.getUserInviteIncome().add(amount));
                    user.updateById();
                }
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean subtractGuCurrency(Long userId, BigDecimal amount, BigDecimal originalAmount, Integer sourceType, Long sourceId, String sourceImage, String sourceName, String desc, String remark) {
        GuUser user = this.getById(userId);
        user.setUserGuCurrency(user.getUserGuCurrency().subtract(amount));
        if (user.updateById()) {
            GuCurrencyRecord currencyRecord = new GuCurrencyRecord();

            currencyRecord.setCrUserId(userId);
            currencyRecord.setCrSteamId(user.getUserSteamId());
            currencyRecord.setCrAmount(amount);
            currencyRecord.setCrOriginalAmount(originalAmount);
            currencyRecord.setCrType(1);
            currencyRecord.setCrSourceType(sourceType);
            currencyRecord.setCrSourceId(sourceId);
            currencyRecord.setCrSourceImage(sourceImage);
            currencyRecord.setCrSourceName(sourceName);
            currencyRecord.setCrDesc(desc);
            currencyRecord.setCrRemark(remark);
            return currencyRecord.insert();
        }
        return false;
    }

    @Override
    public List<UserVo> backUsersByRollId(long rollId, String searchKey) {
        return userMapper.getUsersByRollId(rollId, searchKey);
    }

    @Override
    public void updateuserRevolutions(Integer userId) {
        GuUser guUser = userMapper.selectById(userId);
        guUser.setUserRevolutions(guUser.getUserRevolutions() - 1);
        userMapper.updateById(guUser);
    }

    @Override
    public String getBindingSteamUrl(Long userId) {
        //判断userId是否绑定steamId
        GuUser user = this.getById(userId);
        if (ObjectUtils.isEmpty(user)) {
            throw new GlobalMsgException("未知用户");
        }
        if (!ObjectUtils.isEmpty(user.getUserSteamId())) {
            throw new GlobalMsgException("已绑定steam");
        }

        return SteamLoginUtil.getUrl(systemConfigService.getSystemConfig().getConfigUri() + "/api/user/bindingSteamCallback/" + userId);
    }

    @Override
    public boolean bindingSteam(long userId, String steamId) {
        CommonUtil.checkParams(steamId);
        int count = this.count(new LambdaQueryWrapper<GuUser>() {
            {
                eq(GuUser::getUserSteamId, steamId);
            }
        });
        if (count > 0) {
            //已被绑定
            return false;
        }
        GuUser user = this.getById(userId);

        if (!ObjectUtils.isEmpty(user)) {
            JSONArray playerSummaries = SteamUtil.getPlayerSummaries(steamId, systemConfigService.getSystemConfig().getConfigSteamKey());
            if (CollectionUtils.isEmpty(playerSummaries)) {
                log.error("steam账号未查询到：{}", steamId);
                throw new GlobalMsgException("未知steamId");
            }
            PlayerSummary playerSummary = playerSummaries.getJSONObject(0).toJavaObject(PlayerSummary.class);
            user = this.playerSummary2GuUser(user, playerSummary);
            return user.updateById();
        }
        return false;
    }

    @Override
    public GuUser checkInviteCode(Long userId, String inviteCode) {

        return this.getOne(new LambdaQueryWrapper<GuUser>() {
            {
                eq(GuUser::getUserInviteCode, inviteCode);
                ne(!ObjectUtils.isEmpty(userId), GuUser::getUserInviteCode, userId);
                last("limit 1");
            }
        });
    }

    private GuUser playerSummary2GuUser(GuUser user, PlayerSummary playerSummary) {
        if (ObjectUtils.isEmpty(user)) {
            user = new GuUser();
        }
        user.setUserSteamId(playerSummary.getSteamId());
        user.setUserNickname(playerSummary.getPersonaName());
        user.setUserImage(playerSummary.getAvatarFull());
        return user;
    }

}
